package com.service.infoEntry.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.service.config.utils.*;
import com.service.infoEntry.dao.TeamDao;
import com.service.infoEntry.dao.UserInfoDao;
import com.service.infoEntry.dto.LoginUserDto;
import com.service.infoEntry.dto.UserDto;
import com.service.infoEntry.dto.UserInfoDto;
import com.service.infoEntry.entity.TeamInfo;
import com.service.infoEntry.entity.UserInfo;
import com.service.infoEntry.service.RoleService;
import com.service.infoEntry.service.TeamService;
import com.service.infoEntry.service.UserInfoService;
import com.service.infoEntry.vo.RoleVo;
import com.service.infoEntry.vo.TeamVo;
import com.service.infoEntry.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.service.config.constant.ApiUrlConstants.CLOUD_CAMPUS_TOKEN_URL;
import static com.service.config.constant.ApiUrlConstants.URL_FIRST;
import static com.service.infoEntry.constant.Constant.*;
import static com.service.infoEntry.controller.UserController.clearCache;

@Slf4j
@Service
public class UserInfoServiceImpl implements UserInfoService {
    @Resource
    private UserInfoDao userDao;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    RestTemplate restTemplate;
    @Resource
    private TeamService teamService;
    @Resource
    private TeamDao teamDao;
    @Resource
    private RoleService roleService;
    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public UserInfo queryById(String id) {
        return this.userDao.queryById(id);
    }

    /**
     * 新增数据
     *
     * @param userInfo 实例对象
     * @return 实例对象
     */
    @Override
    public UserInfo insert(UserInfo userInfo) {
        this.userDao.insert(userInfo);
        return userInfo;
    }

    /**
     * 修改数据
     *
     * @param userInfo 实例对象
     * @return 实例对象
     */
    @Override
    public UserInfo update(UserInfo userInfo) {
        userInfo.setOffTime(DateUtils.getNowDate());
        this.userDao.update(userInfo);
        return this.queryById(userInfo.getId());
    }

    /**
     * 修改密码
     *
     * @param userInfoDto 实例对象
     * @return 实例对象
     */
    @Override
    public Result updateUserInfo(UserInfoDto userInfoDto,String userId) throws Exception {
        UserInfo info = userDao.queryById(userId);
        if(null == info)
        {
            return Result.failure(USER_NOT_FOUND,USER_DOES_NOT_EXIST);
        }
        if(null!=userInfoDto.getNewPassword() && !"".equals(userInfoDto.getNewPassword()))
        {
            //修改密码
            UserInfo userInfo = userDao.queryUserInfo(info.getUsername(), userInfoDto.getPassword());
            if(null != userInfo)
            {
                if(userInfoDto.getPassword().equals(userInfoDto.getNewPassword()))
                {
                    return Result.failure(DATA_FORMAT_WRONG,"新旧密码不能一致");
                }
                userDao.updatePassword(userInfoDto);
                Set<String> strings = redisUtil.redisLike(userInfoDto.getId());
                clearCache(strings, redisUtil);
                return Result.ok();
            }
            return Result.failure(PWD_IS_WRONG,ORIGINAL_PASSWORD_INPUT_ERROR);
        }else if((null != userInfoDto.getEMail() && !"".equals(userInfoDto.getEMail())) || (null!=userInfoDto.getTelephone())&& !"".equals(userInfoDto.getTelephone()) || (null!=userInfoDto.getFullName())&& !"".equals(userInfoDto.getFullName())){
            //修改用户信息(手机号和邮箱号)
            if(null != userInfoDto)
            {
                UserInfo userInfo1 = ModelMapperUtil.strictMap(userInfoDto, UserInfo.class);
                if(userInfo1.getTelephone()!=null && userInfo1.getTelephone().length()!=11)
                {
                    return Result.failure(DATA_FORMAT_WRONG,"手机号格式有误");
                }else if(userInfo1.getEMail()!=null)
                {
                    String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
                    Pattern p = Pattern.compile(regEx1);
                    Matcher m = p.matcher(userInfo1.getEMail());
                    if(!m.matches()){
                        return Result.failure(DATA_FORMAT_WRONG,"邮箱格式有误");
                    }
                }
                userDao.update(userInfo1);
                String token=UserTokenManager.generateToken(userInfo1.getId());
                Set<String> strings = redisUtil.redisLike(userInfo1.getId());
                clearCache(strings, redisUtil);
                UserDto userDto = ModelMapperUtil.strictMap(userInfo1, UserDto.class);
                userDto.setDate(new Date()); //登录时间
                redisUtil.setValue(token+userInfo1.getId(), JsonXMLUtils.obj2json(userDto)); // 存入缓存
                return Result.ok().setData(token);
            }
            return Result.failure(DATA_IS_WRONG,DATA_ERROR);
        }
        return Result.failure(DATA_IS_WRONG,DATA_ERROR);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String id) {
        return this.userDao.deleteById(id) > 0;
    }

    @Override
    public UserInfo queryAll(LoginUserDto loginUserDto) {
        return userDao.queryUserInfo(loginUserDto.getAccount(),loginUserDto.getPassword());
    }

    @Override
    public Result register(UserInfoDto userInfoDto, String realIp,String adder) throws Exception {
        UserInfo userInfo = ModelMapperUtil.strictMap(userInfoDto,UserInfo.class);
        UserInfo userInfo1 = userDao.queryUserByName(userInfo.getUsername());
        HashMap map = new HashMap(16);

        if (userInfo1 != null) {
            return Result.failure(USERNAME_REPEAT,USER_NAME_ALREADY_EXISTS_PLEASE_RE_ENTER);
        }

        userInfo.setId(IdUtil.getStringId());
        userInfo.setIp(realIp);
        userInfo.setAddTime(new Date());
        userInfo.setDate(new Date());
        userInfo.setCount(1);
        userInfo.setStatus("0");
        userInfo.setDefaultAddress("待定");
        //创建者创建的新用户，直接拉入团队
        if(userInfoDto.getTeamId() != null && !"".equals(userInfoDto.getTeamId()))
        {
            userInfo.setTeamId(userInfoDto.getTeamId());
        }
        userDao.insert(userInfo);
        //判断是否是团队创建者注册的用户
        if(adder!=null && !"".equals(adder))
        {
            teamService.addUser2Team(userInfoDto.getTeamId(), userInfo.getId(),adder);
        }

        String token = UserTokenManager.generateToken(userInfo.getId());
        map.put("Token",token);
        redisUtil.setValue(token+userInfo.getId(), JsonXMLUtils.obj2json(userInfo)); // 存入缓存
        return Result.ok().setData(map);
    }

    @Override
    public UserInfo queryAlls(LoginUserDto loginUserDto) {
        UserInfo userInfo = userDao.queryUserInfo(loginUserDto.getAccount(), loginUserDto.getPassword());
        return userInfo;
    }

    /**
     * 用户登录获取token
     * @param loginUserDto
     * @param httpServletRequest
     * @return
     * @throws Exception
     */
    @Override
    public HashMap getToken(LoginUserDto loginUserDto, HttpServletRequest httpServletRequest) throws Exception {
        TeamVo teamVo = null;
        RoleVo roleVo = null;
        HashMap map = new HashMap(16);
        UserInfo userInfo = this.queryAll(loginUserDto);
        if (userInfo == null) {
            return null;
        }
        //用户没有默认团队或默认团队不存在时，默认选择其所在团队的随机一个
        List<TeamInfo> teamInfos = teamService.queryTeams(userInfo.getId());
        if (teamInfos.size() > 0) {
            if (userInfo.getTeamId() != null && !"".equals(userInfo.getTeamId())){
                teamVo = teamService.queryTeamByTeamId(userInfo.getTeamId());
                if (teamVo == null) {
                    teamVo = ModelMapperUtil.strictMap(teamInfos.get(0),TeamVo.class);
                    roleVo = roleService.queryRoleInTeam(teamVo.getId(),userInfo.getId());
                    userDao.setDefaultTeam(userInfo.getId(),teamInfos.get(0).getId());
                }else {
                    roleVo = roleService.queryRoleInTeam(teamVo.getId(),userInfo.getId());
                }

                if(null != roleVo)
                {
                    teamVo.setRole(roleVo);
                }
            }else {
                userInfo.setTeamId(teamInfos.get(0).getId());
                userDao.setDefaultTeam(userInfo.getId(),teamInfos.get(0).getId());
                teamVo = ModelMapperUtil.strictMap(teamInfos.get(0),TeamVo.class);
                roleVo = roleService.queryRoleInTeam(teamVo.getId(),userInfo.getId());
                teamVo.setRole(roleVo);
            }
        }
        if (userInfo.getStatus().equals("2") || userInfo.getStatus().equals("3")) {
            map.put("errorCode","您的账号已被封号，详情请查看您的邮箱");
            return map;
        }
        return getHashMap(loginUserDto, httpServletRequest, map, userInfo,teamVo);
    }

    @Override
    public UserVo queryByUserId(String userId) {
        UserVo userVo = userDao.queryByUserId(userId);
        if(null != userVo)
        {
            if(userVo.getDefaultAddress()==null || "".equals(userVo.getDefaultAddress()))
            {
                userVo.setDefaultAddress("待定");
            }
            return userVo;
        }
        return null;
    }

    /**
     * 用户修改默认登录团队
     * @param userId
     * @param teamName
     */
    @Override
    public void changeDefaultTeam(String userId, String teamName) {
        List<TeamInfo> teamInfos = teamService.queryTeams(userId);
        if(teamInfos != null && teamInfos.size()>0)
        {
            teamInfos.forEach(teamInfo -> {
                if (teamInfo.getTeamName().equals(teamName))
                {
                    userDao.changeDefaultTeam(teamInfo.getId(),userId);
                }
            });
        }
    }

    @Override
    public List<UserVo> queryUserFuzzy(String username,String teamId) {
        if(username==null || "".equals(username))
        {
            username="%%";
        }else {
            username = "%"+username+"%";
        }
        List<UserInfo> userInfos = userDao.queryUserFuzzy(username);
        List<UserVo> userVoList = new ArrayList<>();
        if(userInfos!=null && userInfos.size()>0)
        {
            userVoList = ModelMapperUtil.strictMapList(userInfos, UserVo.class);
            //查询团队中所有成员
            List<UserInfo> userInfos1 = teamDao.queryAllUserInTeam(teamId);
            List<UserVo> finalUserVoList = userVoList;
            userInfos1.forEach(userInfo -> {
                List<UserVo> collect = finalUserVoList.stream().filter(userVo -> userVo.getId().equals(userInfo.getId())).collect(Collectors.toList());
                boolean present = collect.stream().findFirst().isPresent();
                if (present){
                    collect.forEach(userVo -> {
                        userVo.setCurrentUser(true);
                    });
                }}
            );
        }
        return userVoList;
    }

    /**
     *  新增用户
     * @param userInfoDto
     * @param realIp
     * @return
     */
    private UserInfo getUserInfo(UserInfoDto userInfoDto, String realIp,String adder) {
        UserInfo userInfo = ModelMapperUtil.strictMap(userInfoDto,UserInfo.class);
        UserInfo userInfo1 = userDao.queryUserByName(userInfo.getUsername());
        if (userInfo1 != null) {
            return null;
        }

        userInfo.setId(IdUtil.getStringId());
        userInfo.setIp(realIp);
        userInfo.setAddTime(new Date());
        userInfo.setDate(new Date());
        userInfo.setCount(1);
        userInfo.setStatus("0");
        if(userInfoDto.getTeamId() != null && !"".equals(userInfoDto.getTeamId()))
        {
            userInfo.setTeamId(userInfoDto.getTeamId());
        }
        userDao.insert(userInfo);
        if(adder!=null && !"".equals(adder))
        {
            teamService.addUser2Team(userInfoDto.getTeamId(), userInfo.getId(),adder);
        }
        return userInfo;
    }


    /**
     * 获取token
     *
     * @param username
     * @param password
     * @param requestHeaders
     * @return
     */
    public String getToken(String username, String password, HttpHeaders requestHeaders, String domain) {
        //获取token
        Map map = new HashMap(16);
        map.put("userName", username);
        map.put("password", password);
        try {
            HttpEntity<Map> requestEntity = new HttpEntity<Map>(map, requestHeaders);
            ResponseEntity<JSONObject> response = restTemplate.exchange(URL_FIRST + domain + CLOUD_CAMPUS_TOKEN_URL, HttpMethod.POST, requestEntity, JSONObject.class);
            return response.getBody().getJSONObject("data").getString("token_id");
        } catch (Exception e) {
            log.error("debug Token ==>" + e.getMessage());
            return null;
        }
    }
    /**
     * 根据强制登录标识符获取token
     * 强制标识符不存在且没有用户登录则直接返回token
     * 用户已登陆则直接返回用户重复登录码
     * @param loginUserDto
     * @param httpServletRequest
     * @param map
     * @param userInfo
     * @return
     * @throws Exception
     */
    private HashMap getHashMap(LoginUserDto loginUserDto, HttpServletRequest httpServletRequest, HashMap map, UserInfo userInfo,TeamVo teamVo) throws Exception {
        String realIp = getRealIp(httpServletRequest);
        UserDto userDto = ModelMapperUtil.strictMap(userInfo, UserDto.class);
        userDto.setIp(realIp); // 来源ip
        userDto.setDate(new Date()); //登录时间
        String token = "";
        Boolean isLogin = loginUserDto.getIsLogin();
        Set<String> strings = redisUtil.redisLike(userInfo.getId());
        if (isLogin != null) {
            if (isLogin) { // 强制登录标识符
                token = UserTokenManager.generateToken(userInfo.getId());
                clearCache(strings, redisUtil);
                HashMap map1 = setUserInfo(map, userInfo, userDto, token,teamVo);
                return map1;
            }
        }
        if (strings.size() >= 1) {
            map.put("errorCode","用户重复登陆");
            return map ;
        }else {
            token = UserTokenManager.generateToken(userInfo.getId());
            HashMap map1 = setUserInfo(map, userInfo, userDto, token,teamVo); //更新用户信息
            return map1;
        }
    }

    /**
     * 更新用户信息并返回token
     * @param map
     * @param userInfo
     * @param userDto
     * @param token
     * @return
     * @throws Exception
     */
    private HashMap setUserInfo(HashMap map, UserInfo userInfo, UserDto userDto, String token,TeamVo teamVo) throws Exception {
        userInfo.setCount(userInfo.getCount()+1);
        userInfo.setDate(userDto.getDate());
        userInfo.setIp(userDto.getIp());
        this.update(userInfo);
        redisUtil.setValue(token+userInfo.getId(), JsonXMLUtils.obj2json(userDto)); // 存入缓存
        map.put("Token",token);
        map.put("user",userDto);
        map.put("team",teamVo);
        return map;
    }

    /**
     * 递归查询缓存中存在验证码
     * @return
     */
    private  String getRandom(){
        String randomNum = CharUtil.getRandomNum(6);
        if (redisUtil.exist(randomNum)) {
            getRandom();
        }
        return randomNum;
    }
    public String getRealIp(HttpServletRequest request) {
        return getString(request);

    }
    public static String getString(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        ip = getString(request, ip);
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    public static String getString(HttpServletRequest request, String ip) {
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        return ip;
    }
}
